﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using com.IronOne.BoardPACWinAppBO.Agenda;
using com.IronOne.BoardPACWinAppBO.General;
using com.IronOne.BoardPACWinAppBO.Meeting;
using com.IronOne.BoardPACWinAppBO.Paper;
using com.IronOne.BoardPACWinAppDAO.Agenda;
using com.IronOne.BoardPACWinAppDAO.Category;
using com.IronOne.BoardPACWinAppService.Sync;
using com.IronOne.BoardPACWinAppService.Xml;
using com.IronOne.BoardPACWinAppUtil.Enums;
using com.IronOne.BoardPACWinAppUtil.Util;

namespace com.IronOne.BoardPACWinAppService.Agenda
{
    public class AgendaService : IAgendaService, IDisposable
    {
        private readonly ISyncService _syncService;
        private readonly IAgendaDAO _agendaDAO;
        private readonly ICategoryDAO _categoryDAO;

        public AgendaService()
        {
            _agendaDAO = new AgendaDAO();
            _syncService = new SyncService();
            _categoryDAO = new CategoryDAO();
        }

        public async Task<MemberModel> GetMemberDetailsById(string memId)
        {
            try
            {
                return await _agendaDAO.GetMemberDetailsById(memId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<List<MemberModel>> GetParticipantsListForMeeting(int meetingId)
        {
            try
            {
                return await _agendaDAO.GetParticipantsListForMeeting(meetingId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<IBuffer> GetPdfDocument(int paperId = 0, int meetingId = 0, byte documentType = 0,
            int versionId = 0)
        {
            try
            {
                //Check the download status
                var paperModel = await _agendaDAO.GetPaperById(paperId);
                paperModel.VersionId = versionId;
                //Annotated version view need this, otherwise always load the latest doc, not versions

                int downStatus = paperModel.DownloadStatus;

                if (downStatus == (int)PaperDownloadStatuses.DownloadError ||
                    downStatus == (int)PaperDownloadStatuses.NotDownloded)
                    return null;

                //Read the physical file decrypt and return it
                return await _agendaDAO.ReadPdfDocument(paperModel, Global.UserId);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public async Task<List<MemberModel>> GetParticipantsListForMeetingWithApprovalStatus(int paperId)
        {
            try
            {
                return await _agendaDAO.GetParticipantsListForMeetingWithApprovalStatus(paperId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<ResponseDataModel> WriteIndividualPartcipStatusToLogTable(LogDataModel ldm)
        {
            try
            {
                return await _agendaDAO.WriteIndividualPartcipStatusToLogTable(ldm);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<LogDataModel> GetIndividualPartcipStatusFromLogTable(int meetingId)
        {
            try
            {
                return await _agendaDAO.GetIndividualPartcipStatusFromLogTable(meetingId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<List<AgendaItem>> GetAgenda(int meetingId)
        {
            try
            {
                return await _agendaDAO.GetAgenda(meetingId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<ResponseDataModel> WriteMemberAttendanceToLogTable(LogDataModel ldm)
        {
            try
            {
                return await _agendaDAO.WriteMemberAttendanceToLogTable(ldm);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<ResponseDataModel> GetPastPapersSearchResults(PastPaperSearchModel ppsm)
        {
            var responseModel = new ResponseDataModel();
            try
            {
                responseModel =
                    await
                        RequestManager.CreateRequest(PrepareParameterBundle(ppsm), RequestURL.PastpaerSearch,
                            ApplicationConstants.RequestType.POST);

                if (responseModel.IsError)
                    return responseModel;

                var ppmList = XmlToModelMapper.PastPapersModelMapper(responseModel.Data.ToString());
                responseModel.Data = ppmList;
            }
            catch (Exception)
            {
                responseModel.IsError = true;
                responseModel.ErrorMessage = "Service general error";
            }
            return responseModel;
        }

        public CookieContainer GetCookieContainer()
        {
            return RequestManager.CookieContainer;
        }

        public async Task<String> GetAprovalOptions(int meetingOrCircular)
        {
            try
            {
                return await _agendaDAO.GetAprovalOptions(meetingOrCircular);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<bool> AddPaperApprovals(string action, string comment, int paperId)
        {
            try
            {
                return await _agendaDAO.AddPaperApprovals(action, comment, paperId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<Tuple<int, bool>> GetAgendaItemApproval(int paperId)
        {
            try
            {
                return await _agendaDAO.GetAgendaItemApproval(paperId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<NewsAndSharedDocModel> GetNewsAndSharedDocsList()
        {
            try
            {
                return await _agendaDAO.GetNewsAndSharedDocsList();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<IBuffer> GetNewsSharedDocPdfDocument(PaperModel globalSelectdItem)
        {
            try
            {
                return await _agendaDAO.GetNewsSharedDocPdfDocument(globalSelectdItem);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<IBuffer> GetPastPaperPdfDocument(PaperModel globalSelectdItem)
        {
            try
            {
                return await _agendaDAO.GetPastPaperPdfDocument(globalSelectdItem);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<PaperModel> GetPaperById(int paperId = 0)
        {
            try
            {
                return await _agendaDAO.GetPaperById(paperId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<bool> UpdatePaperPresentStatus(int meetingId, int paperId)
        {
            try
            {
                return await _agendaDAO.UpdatePaperPresentStatus(meetingId, paperId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<AgendaModel> GetSelectedCategoryAndSubCategory(int categoryId, int subCategoryId)
        {
            try
            {
                var am = new AgendaModel
                {
                    SelectedCategory = await _categoryDAO.GetCategoryByCategoryId(categoryId),
                    SelectedSubCategory = await _categoryDAO.GetSubCategoryBySubCategoryId(subCategoryId)
                };
                return am;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<bool> UpdateViewedPaper(int memberId, int paperId, int versionId)
        {
            try
            {
                return await _agendaDAO.UpdateViewedPaper(memberId, paperId, versionId);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<ResponseDataModel> UploadAnnotation(List<MemberModel> selectedList,
            AgendaItem globalSelectdAgendaItem)
        {
            try
            {
                return await _agendaDAO.UploadAnnotation(selectedList, globalSelectdAgendaItem);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<bool> SaveBookmarks(Dictionary<int, string> bookmarks, string fileName)
        {
            try
            {
                return await _agendaDAO.SaveBookmarks(bookmarks, fileName);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<Dictionary<int, string>> LoadBookmarks(string fileName)
        {
            try
            {
                return await _agendaDAO.LoadBookmarks(fileName);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<StorageFile> GetEmailReadyPaper(string paperName)
        {
            try
            {
                return await _agendaDAO.GetEmailReadyPaper(paperName);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<List<PaperModel>> GetPaperVersionsByPaperId(int paperId, int versionId)
        {
            try
            {
                return await _agendaDAO.GetPaperVersionsByPaperId(paperId, versionId);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public async Task<PaperModel> GetOriginalPaperVersionByPaperId(int paperId)
        {
            try
            {
                return await _agendaDAO.GetOriginalPaperVersionByPaperId(paperId);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public async Task<List<PaperModel>> GetPaperVersionSentByUser(int paperId)
        {
            try
            {
                return await _agendaDAO.GetPaperVersionSentByUser(paperId);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public async Task<List<PaperModel>> GetPaperVersionReceivedByUser(int paperId)
        {
            try
            {
                return await _agendaDAO.GetPaperVersionReceivedByUser(paperId);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public void Dispose()
        {
            Dispose();
        }

        private Dictionary<string, string> PrepareParameterBundle(PastPaperSearchModel ppsm)
        {
            var postData = new Dictionary<string, string>
            {
                {"CategoryId", ppsm.CategoryId + ""},
                {"SubCategoryId", ppsm.SubCategoryId + ""},
                {"KeyWord", ppsm.KeyWord + ""},
                {"MeetingDateFrom", ppsm.MeetingDateFrom + ""},
                {"MeetingDateTo", ppsm.MeetingDateTo + ""},
                {"PaperRefNo", ppsm.PaperRefNo + ""},
                {"PaperStatus", ppsm.PaperStatus + ""}
            };


            return postData;
        }


        public async Task<bool> UpdateIsAnnotBackupNeededOnVersionTable(int paperId, int versionId, int currentPage, bool isBackupNeeded)
        {
            try
            {
                return await _agendaDAO.UpdateIsAnnotBackupNeededOnVersionTable(paperId, versionId, currentPage, isBackupNeeded);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// [0] - IsBackupOnOff
        /// [1] - Backup duration in days
        /// [2] - Formatted datetime of last backup
        /// [3] - Formatted datetime of next backup
        /// </summary>
        /// <returns></returns>
        public async Task<string[]> GetAnnotationBackupDates()
        {
            try
            {
                return await _agendaDAO.GetAnnotationBackupDates();
            }
            catch (Exception)
            {
                throw;
            }
        }


        public async Task<int> GetCurrentPageOfThePaper(int paperId, int versionId)
        {
            try
            {
                return await _agendaDAO.GetCurrentPageOfThePaper(paperId, versionId);
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        public async Task<ResponseDataModel> BackupAnnotations(PaperModel item)
        {
            try
            {
                return await _syncService.BackupAnnotations(item);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<ResponseDataModel> RestoreAnnotations(PaperModel item)
        {
            try
            {
                return await _syncService.AnnotationRestore(item);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<List<PaperModel>> GetBackupNeededAnnotationsList()
        {
            try
            {
                return await _agendaDAO.GetBackupNeededAnnotationsList();
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        public async Task<bool> SetAnnotationBackupDates()
        {
            try
            {
                return await _agendaDAO.SetAnnotationBackupDates();
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        public async Task<List<PaperModel>> DownloadRestoreNeededAnnotationsList()
        {
            try
            {
                return await _syncService.DownloadRestoreNeededAnnotationsList();
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        /*public async Task<bool> UpdateRestoreAnnotationTable(int backupId, PaperDownloadStatuses downloadStatus)
        {
            try
            {
                return await _agendaDAO.UpdateRestoreAnnotationTable(backupId, downloadStatus);
            }
            catch (Exception)
            {
                throw;
            }
        }*/


        public async Task InitiateBackgroundAnnotBackup()
        {
            try
            {
                List<PaperModel> data = await GetBackupNeededAnnotationsList();
                if (data == null || data.Count <= 0) return;

                ResponseDataModel rdm;
                foreach (var item in data)
                {
                    rdm = await BackupAnnotations(item);
                    if (!rdm.IsError)
                        await UpdateIsAnnotBackupNeededOnVersionTable(item.PaperId, item.VersionId, -1, false);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }


        public async Task<int> GetPendingApprovalsPapersList(int days)
        {
            try
            {
                return await _agendaDAO.GetPendingApprovalsPapersList(days);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}